package com.card.match;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.quartz.JobDetail;

import com.card.common.CardContants;
import com.card.common.MessageComm;
import com.card.game.BasePlayer;
import com.card.game.ddz.DdzMatchRoom;
import com.card.game.dn.NnRoom;
import com.card.game.pdk.PdkMatchRoom;
import com.card.game.room.MatchRoom;
import com.card.game.room.RoomManager;
import com.card.game.room.RoomSetting;
import com.card.log.LogType;
import com.card.log.LogUtils;
import com.card.message.JsonMessageCenter;
import com.card.timer.GameTimerManager;
import com.card.user.User;
import com.card.user.UserCurrency.CurrencyKind;
import com.card.user.UserManager;
import com.card.user.UserUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiaoao.net.common.GameConstants;
import com.xiaoao.net.json.message.JsonMessage;
import com.xiaoao.net.utils.PrimaryKey;
import com.xiaoao.net.utils.StringUtil;

/**   
 * @Description: TODO(用一句话描述该文件做什么) 
 * @author sky  
 * @date 2016年11月7日 上午10:13:55 
 * @version V1.0   
 */
public class Match {
	private static final AtomicInteger MatchIDSEQUENCE = new AtomicInteger(100);
	private String id;
	private MatchSetting matchSetting;
	private transient List<String> userList = Lists.newArrayList();
	private MatchState state = MatchState.Wait;
	private long changeStateTime;
	private transient JobDetail matchJobDetail;
	
	private Map<String,RankScore> scoreRank = Maps.newConcurrentMap();
	private List<IMatchRoom> roomList = Lists.newArrayList();
	private int curLun;
	private boolean isStart;
	
	public Match(MatchSetting matchSetting) {
		this.id = PrimaryKey.getIntPrimaryKey("Match")+"";
		this.changeStateTime = System.currentTimeMillis();
		this.matchSetting = matchSetting;
		this.isStart = false;
	}
	public String getId() {
		return id;
	}
	
	public boolean isStart() {
		return state != MatchState.Wait;
	}

	public void addUser(User user) {
		String userId = user.getPrimaryKey();
		if(!userList.contains(userId)) {
			userList.add(userId);
		}
		user.setMatch(this);
		if(isFull()) {
			spendEnterDiamond();
			MatchManager.getInstance().addMatch(matchSetting.getId());
			startMatch();
		}
	}
	
	public boolean isCanLeave() {
		if(this.curLun > 1) {
			return false;
		}
		return userList.size() > getWinNum();
	}
	
	public boolean leaveMatch(String userId) {
		if(isCanLeave()) {
			this.userList.remove(userId);
			this.scoreRank.remove(userId);
			return true;
		}
		return false;
	}
	
	public void checkUserMatch(User user) {
		if(isStart) {
			if(userList.contains(user.getPrimaryKey())) {
				JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_Match_RoundEnd);
				message.addProperty("curLun", curLun);
				message.addProperty("rank", getRank(user.getPrimaryKey()));
				message.addProperty("runNum", getRunTableNum());
				message.addProperty("canLeave", isCanLeave());
				JsonMessageCenter.getInstance().sendMessage(message, user);	
			}else{
				user.setMatch(null);
			}
		}else {
			if(!userList.contains(user.getPrimaryKey())) {
				addUser(user);
			}
			JsonMessage message = new JsonMessage(MessageComm.S2C_Join_Match);
			message.addProperty("matchId", getMatchSetting().getId());
			JsonMessageCenter.getInstance().sendMessage(message, user);
		}
	}
	
	public void spendEnterDiamond() {
		for (int i = userList.size()-1; i >= 0; i--) {
			User user = UserUtils.getUserByPrimaryKey(userList.get(i));
			if(user != null) {
				int spend = getSpend();
				user.userCurrency().spend(CurrencyKind.Diamonds, spend);
				user.sendUserUpdateMessage();
				if(matchSetting.getGameId() == CardContants.GAMETYPE_SH) {
					LogUtils.addSpendLog(user, LogType.CMMJ, spend);
				}else if(matchSetting.getGameId() == CardContants.GAMETYPE_Ddz) {
					LogUtils.addSpendLog(user, LogType.CMDDZ, spend);
				}else if(matchSetting.getGameId() == CardContants.GAMETYPE_TGG) {
					LogUtils.addSpendLog(user, LogType.BMZJH, spend);
				}else if(matchSetting.getGameId() == CardContants.GAMETYPE_Pdk) {
					LogUtils.addSpendLog(user, LogType.CMPDK, spend);
				}else if(matchSetting.getGameId() == CardContants.GAMETYPE_Nn) {
					LogUtils.addSpendLog(user, LogType.BMNN, spend);
				}
			}
		}
	}
	
	public boolean isFull() {
		return userList.size() >= matchSetting.getNum();
	}

	public boolean isContains(String userId) {
		for (int i = userList.size()-1; i >= 0; i--) {
			if(StringUtil.equals(userList.get(i), userId)) {
				return true;
			}
		}
		return false;
	}
	
	private void startMatch() {
		//删除
		setState(MatchState.Runing);
		this.curLun ++;
		this.roomList.clear();
		this.isStart = true;
		Collections.shuffle(userList);
		IMatchRoom room = null;
		for (int i = userList.size()-1; i >= 0 ; i--) {
			String userId = userList.get(i);
			User user = UserUtils.getUserByPrimaryKey(userId);
			if(user != null) {
				if(this.curLun == 1) {
					scoreRank.put(userId, new RankScore(userId));
				}
				room = getFitAreaRoom();
				room.addPlayer(user);
				if(room.isFull()) {
//					room.startGame();
					room = null;
				}
			}
		}
		if(room != null) {
//			room.startGame();
		}
	}
	
	public void setState(MatchState state) {
		this.state = state;
		this.changeStateTime = System.currentTimeMillis();
	}
	
	public void startTime() {
		if(this.matchJobDetail == null) {
			this.matchJobDetail = GameTimerManager.getInstance().addMatchTimer(id);
		}
	}
	
	public void doTimedTask() {
		if(state == MatchState.Runing && this.curLun>0) {
			if(isMatchEnd()) {
				matchSmallEnd();
			}
		}else if(state == MatchState.SmallEnd && getStateTime()>6*GameConstants.SECOND) {
			startMatch();
		}
	}
	private boolean isMatchEnd() {
		for (int i = roomList.size()-1; i >= 0; i--) {
			if(!roomList.get(i).isGameEnd()) {
				return false;
			}
		}
		return true;
	}
	
	private void matchEnd() {
		setState(MatchState.End);
		clearMatch();
	}
	
	private IMatchRoom getFitAreaRoom() {
		if(!roomList.isEmpty()) {
			IMatchRoom room = roomList.get(roomList.size()-1);
			if(room != null && !room.isFull()) {
				return room;
			}
		}
		IMatchRoom room = buildMjMatchRoom();
		roomList.add(room);
		return room;
	}
	private IMatchRoom buildMjMatchRoom() {
		if(matchSetting.getGameId() == CardContants.GAMETYPE_SH) {
			MatchRoom matchRoom = new MatchRoom(this);
			RoomSetting roomSetting = new RoomSetting();
			roomSetting.setRoomType(CardContants.GAMETYPE_SH);
			matchRoom.setRoomSetting(roomSetting);
			RoomManager.getInstance().addRoom(matchRoom);
			matchRoom.startTime();
			return matchRoom;
		}else if(matchSetting.getGameId() == CardContants.GAMETYPE_Ddz){
			DdzMatchRoom matchRoom = new DdzMatchRoom(this);
			RoomSetting roomSetting = new RoomSetting();
			roomSetting.setRoomType(CardContants.GAMETYPE_Ddz);
			matchRoom.setRoomSetting(roomSetting);
			RoomManager.getInstance().addRoom(matchRoom);
			matchRoom.startTime();
			return matchRoom;
		}else if(matchSetting.getGameId() == CardContants.GAMETYPE_TGG){
			MatchRoom matchRoom = new MatchRoom(this);
			RoomSetting roomSetting = new RoomSetting();
			roomSetting.setRoomType(CardContants.GAMETYPE_TGG);
			matchRoom.setRoomSetting(roomSetting);
			RoomManager.getInstance().addRoom(matchRoom);
			matchRoom.startTime();
			return matchRoom;
		}else if(matchSetting.getGameId() == CardContants.GAMETYPE_Nn) {
			MatchRoom matchRoom = new MatchRoom(this);
			RoomSetting roomSetting = new RoomSetting();
			roomSetting.setRoomType(CardContants.GAMETYPE_Nn);
			matchRoom.setRoomSetting(roomSetting);
			RoomManager.getInstance().addRoom(matchRoom);
			matchRoom.startTime();
			return matchRoom;
		}else{
			PdkMatchRoom matchRoom = new PdkMatchRoom(this);
			RoomSetting roomSetting = new RoomSetting();
			roomSetting.setRoomType(CardContants.GAMETYPE_Pdk);
			matchRoom.setRoomSetting(roomSetting);
			RoomManager.getInstance().addRoom(matchRoom);
			matchRoom.startTime();
			return matchRoom;
		}
	}
	
	private long getStateTime() {
		return System.currentTimeMillis()-changeStateTime;
	}
	public void broadMsg(JsonMessage message) {
		for (int i = userList.size()-1; i >= 0; i--) {
			JsonMessageCenter.getInstance().sendMessage(message, userList.get(i));
		}
	}
	
	public void clearMatch() {
		if(this.matchJobDetail != null) {
			GameTimerManager.getInstance().deleteJob(matchJobDetail);
			this.matchJobDetail = null;
		}
		userList.clear();
		for (IMatchRoom areaRoom : roomList) {
			areaRoom.clearGameData();
		}
		roomList.clear();
		MatchManager.getInstance().deleteRunMatch(id);
	}
	
	public int getUserSize() {
		return userList.size();
	}
	public MatchSetting getMatchSetting() {
		return matchSetting;
	}
	public int getSpend() {
		return matchSetting.getEnterDiamond();
	}
	public int getGameId() {
		return matchSetting.getGameId();
	}
	
	public void matchLeave(String userId) {
		if(userList.contains(userId)) {
			userList.remove(userId);
			User user = UserUtils.getUserByPrimaryKey(userId);
			if(user != null) {
				user.setMatch(null);
			}
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_Match_Leave);
			message.addProperty("matchId", getMatchSetting().getId());
			JsonMessageCenter.getInstance().sendMessage(message, user);
			MatchManager.getInstance().broadMatchUpdate();
		}
	}
	private RankScore getRankScore(BasePlayer player) {
		RankScore r = scoreRank.get(player.getUserId());
		if(r == null) {
			r = new RankScore(player);
			scoreRank.put(player.getUserId(), r);
		}
		return r;
	}
	public void updateScore(BasePlayer player) {
		RankScore playerRank = getRankScore(player);
		playerRank.updateScore(player);
	}
	
	public void initScore(BasePlayer player) {
		player.addScore(getRankScore(player).getScore());
	}
	
	public int getRank(String userId) {
		List<RankScore> list = Lists.newArrayList(scoreRank.values());
		Collections.sort(list);
		for (int i = 0; i < list.size(); i++) {
			if(StringUtil.equals(list.get(i).getUserId(), userId)) {
				return i+1;
			}
		}
		return list.size();
	}
	public int getCurLun() {
		return curLun;
	}
	public int getRunTableNum() {
		int num = 0;
		for (int i = roomList.size()-1; i >= 0; i--) {
			if(!roomList.get(i).isGameEnd()) {
				num++;
			}
		}
		return num;
	}
	
	
	private int getWinNum() {
		if(matchSetting.getGameId() == CardContants.GAMETYPE_SH) {
			if(this.curLun == 1) return 8;
			if(this.curLun == 2) return 4;
			if(this.curLun >= 3) return 1;
		}else{
			if(this.curLun == 1) return 3;
			if(this.curLun >= 2) return 1;
		}
		return 1;
	}
	
	public boolean isLastLun() {
		if(matchSetting.getGameId() == CardContants.GAMETYPE_SH) {
			return curLun >= 3;
		}else{
			return curLun >= 2;
		}
	}
	
	private int getWinGold(int rank) {
		int[] rewardGold = matchSetting.getReward();
		if(matchSetting.getGameId() == CardContants.GAMETYPE_SH) {
			if(rank == 0) return rewardGold[0];
			if(rank < 3) return rewardGold[1];
			if(rank < 8) return rewardGold[2];
		}else{
			if(rank < rewardGold.length) {
				return rewardGold[rank];
			}
		}
		return 0;
	}
	
	public void sendMatchResult(String userId,int rank) {
		JsonMessage message = new JsonMessage(MessageComm.S2C_Match_Result);
		message.addProperty("rank", rank+1);
		message.addProperty("winGold", getWinGold(rank));
		message.addProperty("matchName", getMatchSetting().getName());
		JsonMessageCenter.getInstance().sendMessage(message, userId);
	}
	
	public void matchSmallEnd() {
		this.roomList.clear();
		List<RankScore> list = Lists.newArrayList(scoreRank.values());
		Collections.sort(list);
		int winNum = Math.min(getWinNum(), userList.size());
		List<String> winIds = Lists.newArrayList();
		for (int i = 0; i < list.size(); i++) {
			if(i<winNum) {
				winIds.add(list.get(i).getUserId());
			}else{
				sendMatchResult(list.get(i).getUserId(), i);
			}
		}
		if(winNum == 1) {
			if(winIds.size()>0) {
				sendMatchResult(winIds.get(0), 0);
			}
			matchEnd();
			return;
		}
		this.userList.clear();
		this.userList = winIds;
		setState(MatchState.SmallEnd);
//		startMatch();
	}
}
